import { Inject, Provide } from '@midwayjs/core';
import { BaseService } from '../../../common/base.service';
import { UserEntity } from '../entity/user';
import { InjectDataSource, InjectEntityModel } from '@midwayjs/typeorm';
import { DataSource, Repository } from 'typeorm';
import { UserDTO } from '../dto/user';
import { R } from '../../../common/base.error.util';
import { RedisService } from '@midwayjs/redis';
import * as bcrypt from 'bcryptjs';
import { UserRoleEntity } from '../entity/user.role';

@Provide()
export class UserService extends BaseService<UserEntity> {
  @InjectEntityModel(UserEntity)
  userModel: Repository<UserEntity>;

  @InjectEntityModel(UserRoleEntity)
  userRoleModel: Repository<UserRoleEntity>;

  @Inject()
  redisService: RedisService;

  @InjectDataSource()
  defaultDataSource: DataSource;

  getModel(): Repository<UserEntity> {
    return this.userModel;
  }

  async createUser(userDTO: UserDTO) {
    const entity = new UserEntity();
    Object.assign(entity, userDTO.toEntity());
    const { userName } = userDTO;

    const isExist = (await this.userModel.countBy({ userName })) > 0;

    if (isExist) {
      throw R.error('当前用户名已存在');
    }

    // 生成默认密码。
    const password = 'Aa123456';

    // 添加用户，对密码进行加盐加密
    const hashPassword = bcrypt.hashSync(password, 10);

    entity.password = hashPassword;

    await this.defaultDataSource.transaction(async manager => {
      await manager.save(UserEntity, entity)
      await manager.save(
        UserRoleEntity,
        userDTO.roleList.map(roleId => {
          const userRole = new UserRoleEntity();
          userRole.roleId = +roleId;
          userRole.userId = entity.id;
          return userRole;
        })
      );
    })

    return entity.toVO();
  }

  async editUser(userDTO: UserDTO) {
    const { userName, id } = userDTO;
    const user = await this.userModel.findOneBy({ userName });

    if (user && user.id !== id) {
      throw R.error('当前用户名已存在');
    }

    const entity = await this.userModel.findOneBy({ id });
    Object.assign(entity, userDTO);

    const userRolesMap = await this.userRoleModel.findBy({
      userId: userDTO.id,
    });
    
    await this.defaultDataSource.transaction(async manager => {
      await manager.remove(UserRoleEntity, userRolesMap);
      await manager.save(
        UserRoleEntity,
        userDTO.roleList.map(roleId => {
          const userRole = new UserRoleEntity();
          userRole.roleId = +roleId;
          userRole.userId = entity.id;
          return userRole;
        })
      );
      await manager.save(UserEntity, entity)
    })
    return entity.toVO();
  }

  async removeUser(id: number) {
    const entity = await this.userModel.findOneBy({ id });
    const userRolesMap = await this.userRoleModel.findBy({
      userId: id,
    });
    await this.defaultDataSource.transaction(async manager => {
      await manager.remove(UserRoleEntity, userRolesMap);
      await manager.remove(entity)
    })
  }
}
